package com.molamil.outboard {
	import flash.events.ProgressEvent;
	import flash.net.Socket;
	import com.molamil.outboard.shortcut.MidiPositionShortcut;

	/**
	 * @author martindyrby
	 */
	 
	[Event(name="message", type="com.molamil.outboard.MidiEvent")] 
	public class MidiService extends OutboardSocketService {
		
		public static const CONTROL_CHANGE:uint = 176;
		public static const PROGRAM_CHANGE:uint = 192;
		public static const NOTE_ON:uint = 144;
		public static const NOTE_OFF:uint = 128;
		
		public function getMidiControl(controlId:uint, channel:uint) : uint {
			return 0;
		}
		
		public function onMidiNoteOff(noteID:uint, callback:Function, channel:uint = 1) : int {
			var me:MidiEventEntry = MidiEventEntry(outboardhost.createNewEntry(MidiEventEntry));
			me.typeId = noteID;
			me.dispatcher = this;
			me.callback = callback;
			me.channel = channel;
			me.type = MidiEvent.NOTE_OFF;	
			return outboardhost.registerEntry(me);
		}
		
		public function onMidiNoteOn(noteID:uint, callback:Function, channel:uint = 1) : int {
			var me:MidiEventEntry = MidiEventEntry(outboardhost.createNewEntry(MidiEventEntry));
			me.typeId = noteID;
			me.dispatcher = this;
			me.callback = callback;
			me.channel = channel;	
			me.type = MidiEvent.NOTE_ON;
			return outboardhost.registerEntry(me);
		}
		
		public function onMidiControl(controlID:uint, callback:Function, channel:uint = 1) : int {
			var me:MidiEventEntry = MidiEventEntry(outboardhost.createNewEntry(MidiEventEntry));
			me.typeId = controlID;
			me.dispatcher = this;
			me.callback = callback;
			me.channel = channel;
			me.type = MidiEvent.CONTROL_CHANGE;	
			return outboardhost.registerEntry(me);
		}

		public function onMidiProgramChange(programChangeID:uint, callback:Function, channel:uint = 1) : int {
			var me:MidiEventEntry = MidiEventEntry(outboardhost.createNewEntry(MidiEventEntry));
			me.typeId = programChangeID;
			me.dispatcher = this;
			me.callback = callback;
			me.channel = channel;
			me.type = MidiEvent.PROGRAM_CHANGE;	
			return outboardhost.registerEntry(me);
		}
		
		
		public function adjustPosition(controlIDX:uint, controlIDY:uint, name:String, target:*, precision:uint = 0, xOffset:Number = 0, yOffset:Number = 0) : int {
			var mp:MidiPositionShortcut = new MidiPositionShortcut();
			mp.midiService = this;

			mp.controlIDX = controlIDX;
			mp.controlIDY = controlIDY;			
			mp.name = name;
			mp.target = target;
			mp.precision = precision;
			mp.xOffset = xOffset;
			mp.yOffset = yOffset;
			
			return outboardhost.registerShortcut(mp);
		}

		
		
		override protected function socketDataHandler(event : ProgressEvent) : void {

			var rwMessage:String = socket.readUTFBytes(socket.bytesAvailable);
			var messages:Array = rwMessage.split(";");
			var numMessages: uint = messages.length - 1;
			for(var m:int = 0; m < numMessages; ++m) {

				var message:Array = messages[m].split(":");

				var channel:uint = message[0];
				var type:uint = message[1];
				var num:uint = message[2];
				var value:uint = message[3];
				var isBackup:Boolean = message.length == 5;

				dispatchEvent(new MidiEvent(getType(type), num, value, channel))				
			}
		}

		private function getType(type : uint) : String {
			switch(type){
				case CONTROL_CHANGE:
					return MidiEvent.CONTROL_CHANGE;
				case PROGRAM_CHANGE:
					return MidiEvent.PROGRAM_CHANGE;
				case NOTE_OFF:
					return MidiEvent.NOTE_OFF;
				case NOTE_ON:
					return MidiEvent.NOTE_ON;
			}
			return MidiEvent.MESSAGE;
		}
	}
}
